package com.atguigu.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.result.RetVal;
import com.atguigu.result.RetValCodeEnum;
import com.atguigu.util.IpUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

@Component
public class AccessFilter implements GlobalFilter {

    @Value("${filter.whiteFilter}")
    public String whiteFilterList;

    @Autowired
    public RedisTemplate redisTemplate;

    //匹配路径规则
    private AntPathMatcher pathMatcher = new AntPathMatcher();

    /**
     * @param exchange 服务网络交换机 存储着我们的请求和响应信息 它是一个不可变的实例
     * @param chain    网关过滤链表 用于链式调用 设计模式:责任链模式
     * @return 谈谈你对设计模式的理解-->单例模式 工厂模式 代理模式 模板模式 享元模式 大话设计模式
     */

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        /**
         * 3.获取用户信息(包含两个)
         * 获取用户临时id(用户在未登录的时候也可以加入购物车)
         * 获取用户的id信息 如果有用户id说明已经登录过了
         */
        //获取用户临时id(用户在未登录是也能加购物车)
        String userTempId=getUserTempId(request);

        //获取用户登录id信息，如果有id说明已经登陆
        String userId = getUserId(request);

        String path = request.getURI().getPath();
        //对于内部接口 不允许访问 /sku/**
        if (pathMatcher.match("/sku/**",path)){
            return writeDataToBrowser(response);
        }

        for (String whiteFilter : whiteFilterList.split(",")) {
            //判断路径在不在白名单内 在的话去登陆
            if (path.indexOf(whiteFilter)!=-1&&StringUtils.isEmpty(userId)){
                //跳转登录页面 设置响应码
                response.setStatusCode(HttpStatus.SEE_OTHER);
                response.getHeaders().set(HttpHeaders.LOCATION,"http://passport.gmall.com/login.html?originalUrl="+request.getURI());
                return response.setComplete();
            }
        }
        //把用户id保存在header传给shop-web
        if (!StringUtils.isEmpty(userId)||!StringUtils.isEmpty(userTempId)){
            if (!StringUtils.isEmpty(userId)) {
                request.mutate().header("userId",userId);
            }
            if (!StringUtils.isEmpty(userTempId)) {
                request.mutate().header("userTempId",userTempId);
            }
            //把修改过的request重新放入exchange
            return chain.filter(exchange.mutate().request(request).build());
        }
        return chain.filter(exchange);
    }

    private String getUserTempId(ServerHttpRequest request) {
        String userTempId="";
        List<String> headersValueList = request.getHeaders().get("userTempId");
        if (!CollectionUtils.isEmpty(headersValueList)) {
            userTempId=headersValueList.get(0);
        }else {
            HttpCookie cookie = request.getCookies().getFirst("userTempId");
            if (cookie != null){
                userTempId=cookie.getValue();
            }
        }
        return userTempId;
    }

    private Mono<Void> writeDataToBrowser(ServerHttpResponse response) {
        //写信息给浏览器 没有访问权限
        response.getHeaders().add("Content-Type","application/json;charset=UTF-8");
        RetVal<Object> retVal=RetVal.build(null, RetValCodeEnum.NO_PERMISSION);
        byte[] bytes = JSONObject.toJSONString(retVal).getBytes(StandardCharsets.UTF_8);
        DataBuffer dataBuffer = response.bufferFactory().wrap(bytes);
        return response.writeWith(Mono.just(dataBuffer));
    }

    private String getUserId(ServerHttpRequest request) {
        String token="";
        List<String> headersValueList = request.getHeaders().get("token");
        if (!CollectionUtils.isEmpty(headersValueList)) {
            token=headersValueList.get(0);
        }else {
            HttpCookie cookie = request.getCookies().getFirst("token");
            if (cookie != null){
                token=cookie.getValue();
            }
        }
        //通过token从redis中拿到userId
        if(!StringUtils.isEmpty(token)){
            String userKey="user:login:"+token;
            JSONObject loginUserInfoJson = (JSONObject) redisTemplate.opsForValue().get(userKey);
            if (loginUserInfoJson != null) {
                //拿到之前的ip地址
                String redisLoginIp = loginUserInfoJson.getString("loginIp");
                //拿到当前服务器的ip地址
                String ipAddress = IpUtil.getGatwayIpAddress(request);
                if (redisLoginIp.equals(ipAddress)){
                    return loginUserInfoJson.getString("userId");
                }else {
                    return null;
                }
            }
        }
        return null;
    }
}
